package com.biglead.demo.interceptor;


import com.biglead.demo.anno.AccessLimit;
import com.biglead.demo.common.R;
import com.biglead.demo.pojo.UserInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


@Component
@Slf4j
public class AccessLimitInterceptor implements HandlerInterceptor {

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("==============================AccessLimitInterceptor拦截器==============================");
        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (Objects.isNull(accessLimit)) {
                return true;
            }
            int second = accessLimit.second();
            int maxCount = accessLimit.maxCount();
            boolean needLogin = accessLimit.needLogin();
            String uri = request.getRequestURI();
            if (needLogin) {
                String userId = request.getHeader("userId");
//                UserInfo userInfo = getUserInfoFromRequest(request);
//                if (Objects.isNull(userInfo)) {
//                    toRender(response, "请登录");
//                    return false;
//                }
                uri = uri + ":" + userId;
            }
            return toLimit(response, second, maxCount, uri);
        }
        return true;
    }

    // 简单计数器限流
    private boolean toLimit(HttpServletResponse response, int second, int maxCount, String uri) throws IOException {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Integer count = (Integer) valueOperations.get(uri);
        if (Objects.isNull(count)) {
            valueOperations.set(uri, 1, second, TimeUnit.SECONDS);
        } else if (count < maxCount) {
            // 计数器加一
            valueOperations.increment(uri);
        } else {
            log.info("触发限流规则 限流{}秒访问{}次，当前访问{} {}次 ",second,maxCount,count,uri);
            // 超出访问限制
            toRender(response, "当前下单人数排队中 请稍后重试");
            return false;
        }
        return true;
    }

    private void toRender(HttpServletResponse response, String errMessage) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write(new ObjectMapper().writeValueAsString(R.error(errMessage)));
        writer.flush();
        writer.close();
    }
    private UserInfo getUserInfoFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if(StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            String token =  bearerToken.substring(7, bearerToken.length());
            ValueOperations<String, UserInfo> operations = redisTemplate.opsForValue();
            UserInfo userInfo = operations.get(token);
            return userInfo;
        }
        return null;
    }

}
